package com.zyq.util;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTUtil;

import java.beans.Introspector;
import java.io.Serializable;
import java.lang.invoke.SerializedLambda;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.function.Function;
import java.util.regex.Pattern;

/** jwt Util
 * author chics
 * date  2021/5/16
 */
public class JwtUtil {
    private static final Pattern GET_PATTERN = Pattern.compile("^get[A-Z].*");
    private static final Pattern IS_PATTERN = Pattern.compile("^is[A-Z].*");
    public interface Fn<T,R> extends Function<T,R>, Serializable {}

    private static final Integer expired = 120;// 分钟

    private static final String key = "123456789%##@#@";

    /**
     * 创建token
     * @param o 参数Map或者Bean对象
     * @return
     */
    public static String create(Object o){
        DateTime now = DateTime.now();
        Map<String, Object> params = BeanUtil.beanToMap(o);
        params.put(JWT.EXPIRES_AT,now.offsetNew(DateField.MINUTE,expired));// 过期时间
        params.put(JWT.NOT_BEFORE,now);// 生效时间
        params.put(JWT.ISSUED_AT,now);// 签发时间
        return JWTUtil.createToken(params, key.getBytes());
    }

    /**
     * 验证token
     * @param token
     * @return
     */
    public static boolean verify(String token){
        JWT jwt = parse(token);
        jwt.setKey(key.getBytes());
        return jwt.verify() && jwt.validate(expired);
    }

    /**
     * 获取参数bean
     * @param token
     * @param <T>clazz
     * @return
     */
    public static <T>T getPayload(String token,Class<T> clazz){
        return BeanUtil.toBean(parse(token).getPayload().getClaimsJson(),clazz);
    }

    /**
     * 获取参数值
     * @param name lambda获取Bean属性名称
     * @return
     */
    public static Object getValue(String token,String name){
        return parse(token).getPayload(name);
    }

    /**
     * 解析token
     * @param token
     * @return
     */
    public static JWT parse(String token){
        return JWTUtil.parseToken(token);
    }

    /**
     * lambda获取属性
     * @param fn
     * @param <T>
     * @return
     */
    public static <T>String fnToFieldName(Fn<T,Object> fn){
        try {
            Method method = fn.getClass().getDeclaredMethod("writeReplace");
            method.setAccessible(true);
            SerializedLambda serializedLambda = ((SerializedLambda) method.invoke(fn));
            String name = serializedLambda.getImplMethodName();
            if (GET_PATTERN.matcher(name).matches()){
                name = name.substring(3);
            }else if (IS_PATTERN.matcher(name).matches()){
                name = name.substring(2);
            }
            return Introspector.decapitalize(name);
        }catch (ReflectiveOperationException e){
            throw new RuntimeException(e);
        }
    }
}

